package com.goldman.base.common.sys.interceptor;

import com.goldman.base.common.sys.exception.BusinessException;
import com.goldman.http.common.s2s.model.ErrorCode;
import com.goldman.http.common.s2s.model.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;

@Slf4j
@RestControllerAdvice
public class ExceptionInterceptor {

    @ExceptionHandler(ServletRequestBindingException.class)
    public ResponseData handleServletRequestBindingException(ServletRequestBindingException ex) {
        log.warn("parameter error", ex);
        return ResponseData.failed(ErrorCode.ARG_ERROR.getMsg());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseData handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.warn("parameter error", ex);
        String defaultMessage = ErrorCode.ARG_ERROR.getMsg();
        // 获取异常信息
        BindingResult exceptions = ex.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                String errorFirld = fieldError.getField();
                errorFirld = errorFirld.substring(errorFirld.lastIndexOf(".") + 1);
                if (fieldError.getDefaultMessage().toLowerCase().contains(errorFirld.toLowerCase())) {
                    defaultMessage = fieldError.getDefaultMessage();
                } else {
                    defaultMessage = String.format("param: %s, %s", errorFirld, fieldError.getDefaultMessage());
                }
                return ResponseData.argError(defaultMessage);
            }
        }
        return ResponseData.argError(defaultMessage);
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseData handle404(NoHandlerFoundException ex) {
        log.warn("404 not found", ex);
        return ResponseData.failed("404 not found");
    }

    @ExceptionHandler(BusinessException.class)
    public ResponseData hanldeBusinessExcetpion(BusinessException ex) {
        log.warn("business exception", ex);
        return ResponseData.sysError(ex.getMsg(), ex.getError());
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseData handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        return ResponseData.failed(HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase());
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResponseData handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException ex) {
        log.warn("Media Type Not Supported", ex);
        return ResponseData.failed(HttpStatus.UNSUPPORTED_MEDIA_TYPE.getReasonPhrase());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseData handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.warn("Required request body is missing", ex);
        return ResponseData.argError("request body is missing");
    }

    @ExceptionHandler(Throwable.class)
    public ResponseData handleError(Throwable e) {
        log.error("uncaught error", e);
        return ResponseData.failed("uncaught error");
    }
}